package hsr;

import java.util.ArrayList;

import processing.core.PApplet;
import processing.core.PVector;
import shape.Polyhedra;
import shape.PolyhedraFace;

public class BSP {

	ArrayList<Polyhedra> polyhedrons = new ArrayList<Polyhedra>();
	BinaryNode<PolyhedraFace> rootNode = null;

	public BSP(ArrayList<Polyhedra> polyhedrons) {
		this.polyhedrons = polyhedrons;
	}

	private void buildTree() {

		if (rootNode == null) {
			ArrayList<PolyhedraFace> faces = new ArrayList<PolyhedraFace>(
					polyhedrons.size());
			for (Polyhedra p : polyhedrons) {
				faces.addAll(p.getFaces());
			}

			rootNode = buildSubTree(faces);
		}

	}

	private BinaryNode<PolyhedraFace> buildSubTree(
			ArrayList<PolyhedraFace> faces) {

		// First base case of recursive call
		if (faces.isEmpty())
			return null;

		PolyhedraFace firstNode = faces.get(0);
		BinaryNode<PolyhedraFace> rootNode2 = new BinaryNode<PolyhedraFace>(
				firstNode);
		faces.remove(firstNode);

		// Second base case of recursive call : There was only one node in the
		// list
		if (faces.isEmpty())
			return rootNode2;

		ArrayList<PolyhedraFace> positive = new ArrayList<PolyhedraFace>();
		ArrayList<PolyhedraFace> negative = new ArrayList<PolyhedraFace>();

		for (PolyhedraFace face : faces) {
			int eval = 0;
			try {
				eval = rootNode2.getContent().get(0).getPlaneEquation().f(face);
			} catch (Exception e) {
				// This happens when the plane passed to f() is contained in the
				// plane described by the plane equation
				rootNode2.getContent().add(face);
				continue;
			}
			if (eval > 0) {
				positive.add(face);
			} else if (eval < 0) {
				negative.add(face);
			} else {
				ArrayList<PolyhedraFace> division = face.cutByPlane(rootNode2
						.getContent().get(0).getPlaneEquation());
				try {
					if (rootNode2.getContent().get(0).getPlaneEquation()
							.f(division.get(0)) >= 0
							&& rootNode2.getContent().get(0).getPlaneEquation()
									.f(division.get(1)) < 0) {
						positive.add(division.get(0));
						negative.add(division.get(1));
					} else {
						positive.add(division.get(1));
						negative.add(division.get(0));
					}
				} catch (Exception e) {
					System.out.println("THIS SHOULD NEVER HAPPEN AHHH RUN!");
				}
			}
		}

		rootNode2.setRightNode(buildSubTree(positive));
		rootNode2.setLeftNode(buildSubTree(negative));

		return rootNode2;
	}

	public void draw(PApplet canvas, PVector cameraPosition) {
		buildTree();
		drawNode(canvas, cameraPosition, rootNode);
	}

	public void drawNode(PApplet canvas, PVector cameraPosition,
			BinaryNode<PolyhedraFace> rootNode) {
		if (rootNode == null)
			return;
		if (rootNode.getContent().get(0).getPlaneEquation().f(cameraPosition) < 0) {
			drawNode(canvas, cameraPosition, rootNode.getRightNode());
			for (PolyhedraFace f : rootNode.getContent())
				f.draw(canvas);
			drawNode(canvas, cameraPosition, rootNode.getLeftNode());
		} else {
			drawNode(canvas, cameraPosition, rootNode.getLeftNode());
			for (PolyhedraFace f : rootNode.getContent())
				f.draw(canvas);
			drawNode(canvas, cameraPosition, rootNode.getRightNode());
		}
	}

}
